/* 
 * File:   OpenglWindow.cpp
 * Author: Marco Ambu
 * 
 * Created on September 30, 2010, 6:26 PM
 */

#include "OpenglWindow.h"
#include <GL/glut.h>

OpenglWindow::OpenglWindow()
  : title_(""), width_(300), height_(300)
  , useDoublebuffer_(false)
  , currentRotationX_(0)
  , currentRotationY_(0)
  , callList_(1)
{
}

OpenglWindow& OpenglWindow::setTitle(const std::string& title)
{
  title_ = title;
  return *this;
}
OpenglWindow& OpenglWindow::setWidth(std::size_t width)
{
  width_ = width;
  return *this;
}
OpenglWindow& OpenglWindow::setHeight(std::size_t height)
{
  height_ = height;
  return *this;
}
OpenglWindow& OpenglWindow::setDoublebuffer(bool use)
{
  useDoublebuffer_ = use;
  return *this;
}
OpenglWindow& OpenglWindow::setCurrentRotation(int x, int y)
{
  currentRotationX_ = x;
  currentRotationY_ = y;
  return *this;
}

void OpenglWindow::create()
{
  GLenum type = GLUT_RGB | GLUT_DEPTH;
  type |= useDoublebuffer_ ? GLUT_DOUBLE : GLUT_SINGLE;
  glutInitDisplayMode(type);
  glutInitWindowSize(width_, height_);
  glutCreateWindow(title_.c_str());

  float position[] = {0.0, 3.0, 3.0, 0.0};
  float local_view[] = {0.0};
  float ambient[] = {0.1745, 0.01175, 0.01175};
  float diffuse[] = {0.61424, 0.04136, 0.04136};
  float specular[] = {0.727811, 0.626959, 0.626959};

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);

  glLightfv(GL_LIGHT0, GL_POSITION, position);
  glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);

  glFrontFace(GL_CW);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_AUTO_NORMAL);
  glEnable(GL_NORMALIZE);

  glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
  glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
  glMaterialf(GL_FRONT, GL_SHININESS, 0.6*128.0);

  glClearColor(0.5, 0.5, 0.5, 1.0);
  glColor3f(1.0, 1.0, 1.0);
}

void OpenglWindow::addShape(const OpenglShape& shape)
{
  unsigned int listId = callList_.size();
  callList_.push_back(listId);
  glNewList(listId, GL_COMPILE);
  shape.display();
  glEndList();
}

void OpenglWindow::onReshapeEvent(int width, int height)
{
  width_ = width;
  height_ = height;
  glViewport(0, 0, (GLint)width, (GLint)height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-6.0, 6.0, -6.0, 6.0, -1.0, 10.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}
void OpenglWindow::onDisplayEvent()
{
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

  glPushMatrix();

  glTranslatef(0.0, 0.0, -5.0);
  glRotatef(currentRotationY_, 0.0,1.0,0.0);
  glRotatef(currentRotationX_, 1.0,0.0,0.0);

  for (unsigned int i = 0; i < callList_.size(); ++i)
    glCallList(callList_[i]);

  glPopMatrix();

  if (useDoublebuffer_)
  {
    glutSwapBuffers();
  }
  else
  {
    glFlush();
  }
}
void OpenglWindow::onKeyEvent(unsigned char key, int x, int y)
{
}
void OpenglWindow::onSpecialEvent(int key, int x, int y)
{
  switch (key) {
    case GLUT_KEY_UP:
      currentRotationX_ -= 20.0;
      glutPostRedisplay();
      break;
    case GLUT_KEY_DOWN:
      currentRotationX_ += 20.0;
      glutPostRedisplay();
      break;
    case GLUT_KEY_LEFT:
      currentRotationY_ -= 20.0;
      glutPostRedisplay();
      break;
    case GLUT_KEY_RIGHT:
      currentRotationY_ += 20.0;
      glutPostRedisplay();
      break;
    }
}
